/* do not edit automatically generated by mc from mcStream.  */
/* mcStream.mod provides an interface to create a file from fragments.

Copyright (C) 2015-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius@glam.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include <stdbool.h>
#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#   include "GStorage.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _mcStream_H
#define _mcStream_C

#   include "GFIO.h"
#   include "Glibc.h"
#   include "GIndexing.h"
#   include "GDynamicStrings.h"
#   include "GFormatStrings.h"
#   include "GSYSTEM.h"
#   include "GStorage.h"
#   include "Galists.h"
#   include "GSFIO.h"
#   include "GM2RTS.h"

typedef FIO_File *mcStream_ptrToFile;

#   define maxBuffer 4096
static alists_alist listOfFiles;
static Indexing_Index frag;
static FIO_File destFile;
static bool seenDest;

/*
   openFrag - create and open fragment, id, and return the file.
              The file should not be closed by the user.
*/

extern "C" FIO_File mcStream_openFrag (unsigned int id);

/*
   setDest - informs the stream module and all fragments must be copied
             info, f.
*/

extern "C" void mcStream_setDest (FIO_File f);

/*
   combine - closes all fragments and then writes them in
             order to the destination file.  The dest file
             is returned.
*/

extern "C" FIO_File mcStream_combine (void);

/*
   removeFiles - remove any fragment.
*/

extern "C" void mcStream_removeFiles (void);

/*
   removeLater -
*/

static DynamicStrings_String removeLater (DynamicStrings_String filename);

/*
   removeNow - removes a single file, s.
*/

static void removeNow (DynamicStrings_String s);

/*
   createTemporaryFile -
*/

static FIO_File createTemporaryFile (unsigned int id);

/*
   copy - copies contents of f to the destination file.
*/

static void copy (mcStream_ptrToFile p);


/*
   removeLater -
*/

static DynamicStrings_String removeLater (DynamicStrings_String filename)
{
  alists_includeItemIntoList (listOfFiles, reinterpret_cast<void *> (filename));
  return filename;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   removeNow - removes a single file, s.
*/

static void removeNow (DynamicStrings_String s)
{
  if ((libc_unlink (DynamicStrings_string (s))) != 0)
    {}  /* empty.  */
}


/*
   createTemporaryFile -
*/

static FIO_File createTemporaryFile (unsigned int id)
{
  DynamicStrings_String s;
  FIO_File f;
  int p;

  s = DynamicStrings_InitString ((const char *) "/tmp/frag-%d-%d.frag", 20);
  p = libc_getpid ();
  s = removeLater (FormatStrings_Sprintf2 (s, (const unsigned char *) &p, (sizeof (p)-1), (const unsigned char *) &id, (sizeof (id)-1)));
  f = SFIO_OpenToWrite (s);
  return f;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   copy - copies contents of f to the destination file.
*/

static void copy (mcStream_ptrToFile p)
{
  typedef struct copy__T1_a copy__T1;

  struct copy__T1_a { char array[maxBuffer+1]; };
  copy__T1 buffer;
  unsigned int b;
  DynamicStrings_String s;
  FIO_File f;

  if (p != NULL)
    {
      f = (*p);
      s = DynamicStrings_InitStringCharStar (FIO_getFileName (f));
      FIO_Close (f);
      f = SFIO_OpenToRead (s);
      while (! (FIO_EOF (f)))
        {
          b = FIO_ReadNBytes (f, maxBuffer, &buffer);
          b = FIO_WriteNBytes (destFile, b, &buffer);
        }
      FIO_Close (f);
    }
}


/*
   openFrag - create and open fragment, id, and return the file.
              The file should not be closed by the user.
*/

extern "C" FIO_File mcStream_openFrag (unsigned int id)
{
  FIO_File f;
  mcStream_ptrToFile p;

  f = createTemporaryFile (id);
  Storage_ALLOCATE ((void **) &p, sizeof (FIO_File));
  (*p) = f;
  Indexing_PutIndice (frag, id, reinterpret_cast<void *> (p));
  return f;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   setDest - informs the stream module and all fragments must be copied
             info, f.
*/

extern "C" void mcStream_setDest (FIO_File f)
{
  seenDest = true;
  destFile = f;
}


/*
   combine - closes all fragments and then writes them in
             order to the destination file.  The dest file
             is returned.
*/

extern "C" FIO_File mcStream_combine (void)
{
  if (! seenDest)
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  Indexing_ForeachIndiceInIndexDo (frag, (Indexing_IndexProcedure) {(Indexing_IndexProcedure_t) copy});
  mcStream_removeFiles ();
  return destFile;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   removeFiles - remove any fragment.
*/

extern "C" void mcStream_removeFiles (void)
{
  alists_foreachItemInListDo (listOfFiles, (alists_performOperation) {(alists_performOperation_t) removeNow});
  alists_killList (&listOfFiles);
  listOfFiles = alists_initList ();
}

extern "C" void _M2_mcStream_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
  listOfFiles = alists_initList ();
  seenDest = false;
  frag = Indexing_InitIndex (1);
}

extern "C" void _M2_mcStream_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}
